JVM 实战
- 虚拟机环境的JVM讲解
- 测试环境的JVM讲解
如何生成GC日志文件
-verbose:gc -Xloggc:/usr/local/jvmlog/gc.log
-XX:+PrintGCTimeStamps -XX:+PrintGCDetails./jmap -dump:format=b,file=t/usr/local/tmp/test.dump pid
生成dump文件通过自带的visualVM生成即时的快照dump文件
启动server配置 OOM自动生成快照dump文件
其他相关参数调优:
https://www.cnblogs.com/redcreen/archive/2011/05/04/2037057.html
备注
CMS 情况我试过了,分配的不按这个逻辑来啊,默认newratio是2,但是分配了500M给堆区,但是老年代直接占了413M,比例成了5:1了
不同GC回收器生成的日志格式都不一样,要具体分析
流程
运行在linux虚拟机 物理内存4G的环境下,JDK1.7
- 配置 tomcat的catAlina.sh的 jvm 参数
- 启动之后,看内存的分配,和GC回收器的种类
- 查看和分析GC日志
配置jvm 参数
在catalina.sh 的头部配置参数。
- 设置堆初始化大小500M, 永久代初始化64M
- 设置年轻代 Eden:S0=4
- 设置日志输出文件渠道
- 设置S(to)进入老年代的年龄是15次JAVA_OPTS="-server -Xms500m -Xmx1500m -XX:PermSize=64m -XX:MaxPermSize=256m -XX:SurvivorRatio=4-verbose:gc -Xloggc:/usr/local/jvmlog/gc.log-Djava.awt.headless=true-XX:+PrintGCTimeStamps -XX:+PrintGCDetails-Dsun.rmi.dgc.server.gcInterval=600000 -Dsun.rmi.dgc.client.gcInterval=600000-XX:MaxTenuringThreshold=15"
查看内存分配
查看堆内存信息
- 回收器类型 JDK 1.7 默认是 Mark Sweep Compact
- 最大堆区:设置的1500M
- 最小500M, 而默认的新生代 和老年代的比例是2,所以 新生代的大小是500/3=166M
- Eden:S=4,所以S0=166/6=27.75, Eden: 27.75*4=111M, 111 +27.75 +27.75=166
查看和分析 GC日志
首先看次数,可以看出Yong GCT 为18次,而日志中刚好也是18行,默认Yong GC 是简写的,FullGC才会写全称。
分析第一行 Eden+S0 从113792k MinorGC 后变成13544K,压缩后的总容量为142208(也就是111M+27.75M=138M*1024= 141312K)
测试环境实战
更换测试环境的JDK路径
因为之前用的是很老的 1.6的JDK版本,都没有各种工具的,所以修改 nano catalina.sh 文件,添加了下面的,指定了 JDK 路径,而不是用java home的 1.6的JDK,结果启动成功了
JVM 参数分析 jinfo -flags pid
./jinfo -flags 20817
主要参数:
-XX:PermSize=512M -XX:MaxPermSize=4096M
分析:
1) 没有记录JVM日志的操作,而且没有内存溢出的报告
2) 而且没有设置JVM Xms Xmx的大小,浪费了
3) Perm区由没有必要设置为这么大?
GC策略查询 jmap -heap pid
Parallel GC 4线程,吞吐量优先。
问题:
1) 没有默认赋值 最小空闲 和最大空闲比例,系统不会跟随工作量调整JVM的堆区的大小,只有当Minor GC的时候 才会resize,而且一旦上调之后便不会下调,因为MaxHeaop是100,也就是是否有必要动态调整JVM 堆区的大小,其实这和 Xmn Xmx值设置为一样是一个道理。但是设置 Xmn Xmx可以避免前期因为太小而FullGC的情况,优化为40% 70%
2) 很奇怪没有按照 8:1的比例,而且S from 和S to大小不一样 S0:S1的容量是 2:1,但是有一个区是0的没错。
3) Perm区 使用率只有24%,有点浪费空间,很好奇为什么设置这么大
空间分配容量查询
./jstat -gccapacity 20817
因为采用的是 Pallel GC所以是以吞吐量为优先,根据参数动态调整。
内存实际使用和GC情况
1) gcutil 可以看出 利用率最低的就是 Perm区了,只有24%,没必要分配这么大的空间给他。
2) FGC的耗时有点长,平均达到了2s,有必要看一下详细情况,以及check下 nginx的超时设置,会不会导致2s的访问失败
利用jmap导出并查看dump包
./jmap -dump:live,format=b,file=/usr/developer/huangForBackUp/testEnv.bin 20817
gc log分析
性能优化
1) 添加jvm日志输出,更加仔细的查看每次GC的活动
2) check nginx的超时设置,从而判断有没有失败的请求(这是GCT的上限)(链接nginx上限是3s 钟 后台处理 和 后台返回的超时时间各位300s,所以只要GC时间在3s以内就几乎不会请求失败)
3) 根据GC日志降低 FULLGC的次数和最大时长
解决方案:实际上通过调大Xms 避免了最开始期间的FULLGC,其实意义并不大。因为老的JVM方案,经过1个小时之后JVM自动也调整到这个水平。或者可以说本来就已经到了很棒的水平了
1) 添加日志输出,在catelina.sh 中添加参数
JAVA_OPTS=”$JAVA_OPTS -server -Xms2048m -XX:PermSize=256M -XX:MaxPermSize=1024M
-verbose:gc -Xloggc:/usr/developer/huangForBackUp/testgc.log
-XX:+PrintGCTimeStamps -XX:+PrintGCDetails -XX:MaxTenuringThreshold=15”
2) 初始化设置Xms的大小 Xmx的大小,以及ratio,因为最开始的2次FullGC都是因为初始化的永久代太小导致的,后面等永久代保存好了之后,就不容易FULLGC了。
看日志里面 Parellel稳定期间 分配给年轻代的大小稳定在 1.3G左右,老年代的大小在700M左右,直接最小为2G,最大4G
其实通过日志可以发现在2G大小的时候,Minor GC的时间稳定在 0.35秒左右,是一个可以接受的时间。
3) 调优后 初期表现良好,当JVM启动2分钟之后开始稳定了
深层优化
网站类型的服务器应该优先采用CMS作为垃圾回收类型
没有大量的数据很难做出调优方案,因为本来就已经性能不错了